#include "bs_protocol.h"

#define BS_WRITER_CLK_LENGTH           (BS_CHUNK_SIZE+2)
#ifndef PWM_SINGLE_PULSE_MODE
uint32_t          ice_clk0_buff[BS_WRITER_CLK_LENGTH];
uint32_t          ice_clk1_buff[BS_WRITER_CLK_LENGTH];
#endif

static uint8_t    ch0_transmit_buf[512];
static uint8_t    ch1_transmit_buf[512];
static uint8_t    ch0_receive_buf[512];
static uint8_t    ch1_receive_buf[512];

static bs_writer_drv_t spi_dev0 = {
    .spix       = SPI0,
    .timx       = TIMER1,
    .tx_buf     = ch0_transmit_buf,
    .rx_buf     = ch0_receive_buf,
    .tx_count   = 0,
    .rx_count   = 0,
    .clock_data = NULL,   /* TODO */
    .dma_chan     = {
        [BS_DMA_CLOCK]    = {DMA0, DMA_CH1, DMA_SUBPERI3},
        [BS_DMA_DATA_OUT] = {DMA1, DMA_CH3, DMA_SUBPERI3},
        [BS_DMA_DATA_IN]  = {DMA1, DMA_CH2, DMA_SUBPERI3},
    }
};

static bs_writer_drv_t spi_dev1 = {
    .spix       = SPI1,
    .timx       = TIMER2,
    .tx_buf     = ch1_transmit_buf,
    .rx_buf     = ch1_receive_buf,
    .tx_count   = 0,
    .rx_count   = 0,
    .clock_data = NULL,    /* TODO */
    .dma_chan      = {
        [BS_DMA_CLOCK]    = {DMA0, DMA_CH2, DMA_SUBPERI5},
        [BS_DMA_DATA_OUT] = {DMA0, DMA_CH4, DMA_SUBPERI0},
        [BS_DMA_DATA_IN]  = {DMA0, DMA_CH3, DMA_SUBPERI0},
    }
};


void bs_protocol_config(bs_writer_ctx_t *ctx, unsigned char channel)
{
    if (channel == 0)
    {
        ctx->drv = &spi_dev0;
    } else if (channel == 1)
    {
        ctx->drv = &spi_dev1;
    } else {
        return;
    }

#ifndef PWM_SINGLE_PULSE_MODE
    uint32_t *clk_data;
    int i=0;
    clk_data = ctx->drv->clock_data;
    // 初始化 pwm 脉冲
    for(i=0; i<8; i++)
    {
      clk_data[i] = TIMER1_PWM_DUTY;
    }
    clk_data[i++] = 0;
    for(; i<BS_WRITER_CLK_LENGTH-1; i++)
    {
        clk_data[i] = TIMER1_PWM_DUTY;
    }
    clk_data[i] = 0;
#endif
}



/*!
    \brief      查询 pwm dma传输状态 及 spi传输状态
    \param[in]  none
    \param[out] none
    \retval     0: 忙，1:传输完成
*/
int __v1_protocol_ioctl(bs_writer_ctx_t *ctx,  bs_writer_trans_t cmd)
{
    int status=0;
    uint32_t size;
    uint32_t time_out = WRITE_TIME_OUT;
    switch(cmd)
    {
    case IOC_WR_END:
        size = ctx->drv->tx_count;
        // 查询 PWM 的DMA状态
        if(ctx->channel == 0) {
            status = dma_flag_get(DMA0, DMA_CH1, DMA_INTF_FTFIF);
        } else {
            status = dma_flag_get(DMA0, DMA_CH2, DMA_INTF_FTFIF);
        }
        if (status)
        {
            ctx->drv->clock_data[size*16+2-1] = ctx->drv->clock_data[0];
            while(SET == spi_i2s_flag_get(ctx->drv->spix, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            }
            spi_dma_disable(ctx->drv->spix, SPI_DMA_TRANSMIT);
            status = 1;

            if(time_out == 0)
            {
                ctx->schedu = WRITER_WR_TIME_OUT;
            }
            ctx->drv->clock_data[size*16+2-1] = ctx->drv->clock_data[0];
        }
    break;

    default:
    break;
    }
    return status;
}


/*!
    \brief      pwm+dma: 阻塞写入
    \param[in]  none
    \param[out] none
    \retval     0: success，1:timeout
*/
int __v1_bs_protocol_write_sync(bs_writer_ctx_t *ctx, unsigned char *buf, int size)
{
	uint8_t chan = ctx->channel;
    uint32_t time_out = 0;
    if (chan == 0)
    {
        /* enable 3Line send */
        SPI_CTL0(SPI0) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
        while(size--)
        {
            // while(0 == SPI_STAT(SPI0) & SPI_FLAG_TBE);
            SPI_DATA(SPI0) = (uint32_t)(*buf++);
            
            /* reset PWM&DMA */    
            /* disable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH1) &= ~DMA_CHXCTL_CHEN;

            /* disable TIM update event */
            TIMER_DMAINTEN(TIMER1) &= (~(uint32_t)(TIMER_DMA_UPD));
            
            /* reset DMA channel registers */
            dma_flag_clear(DMA0, DMA_CH1, DMA_CHINTF_RESET_VALUE);

            /* configure dma number (8bit data + 1bit zero)*/
            DMA_CHCNT(DMA0, DMA_CH1) = 9;

            /* enable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH1) |= DMA_CHXCTL_CHEN;
            
            /* restart PWM */
            TIMER_DMAINTEN(TIMER1) |= (uint32_t) TIMER_DMA_UPD;

            /* wait PWM transmit complete & spi receive data */
            time_out = WRITE_TIME_OUT;
            while(RESET == dma_flag_get(DMA0, DMA_CH1, DMA_INTF_FTFIF))
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(SET == spi_i2s_flag_get(SPI0, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            }
            // (void)SPI_DATA(SPI0);
            if(time_out == 0) return 1;   // time_out
        }
    } else if (chan==1)
    {
        /* enable 3Line send */
        SPI_CTL0(SPI1) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
        while(size--)
        {
            // while(0 == SPI_STAT(SPI1) & SPI_FLAG_TBE);
            SPI_DATA(SPI1) = (uint32_t)(*buf++);
            
            /* reset PWM&DMA */    
            /* disable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH2) &= ~DMA_CHXCTL_CHEN;

            /* disable TIM update event */
            TIMER_DMAINTEN(TIMER2) &= (~(uint32_t)(TIMER_DMA_UPD));
            
            /* reset DMA channel registers */
            dma_flag_clear(DMA0, DMA_CH2, DMA_CHINTF_RESET_VALUE);

            /* configure dma number (8bit data + 1bit zero)*/
            DMA_CHCNT(DMA0, DMA_CH2) = 9;

            /* enable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH2) |= DMA_CHXCTL_CHEN;
            
            /* restart PWM */
            TIMER_DMAINTEN(TIMER2) |= (uint32_t) TIMER_DMA_UPD;

            /* wait PWM transmit complete & spi receive data */
            time_out = WRITE_TIME_OUT;
            while(RESET == dma_flag_get(DMA0, DMA_CH2, DMA_INTF_FTFIF))
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(SET == spi_i2s_flag_get(SPI0, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            }
            // (void)SPI_DATA(SPI0);
            if(time_out == 0) return 1;   // time_out
        }
    } else {return 1;}

    return 0;

}


/*!
    \brief      利用dma发送批量数据，需要配合 pwm+dma
    \param[in]  none
    \param[out] none
    \retval     0: success
*/
void __v1_protocol_write_async(bs_writer_ctx_t *ctx, unsigned char *buf, int size)
{
    // 1. 填充内容
    register uint8_t temp;
    bs_writer_drv_t *drv = ctx->drv;
    register uint8_t *dst = (uint8_t *)drv->tx_buf;
    uint32_t spix = drv->spix;
    uint32_t timx = drv->timx;
    uint32_t trans_dma = drv->dma_chan[BS_DMA_DATA_OUT].dmax;
    dma_channel_enum trans_chan = (dma_channel_enum)drv->dma_chan[BS_DMA_DATA_OUT].chan;
    dma_subperipheral_enum trans_sub = (dma_subperipheral_enum)drv->dma_chan[BS_DMA_DATA_OUT].sub_peri;

    // pwm dma
    uint32_t clk_dma = drv->dma_chan[BS_DMA_CLOCK].dmax;
    dma_channel_enum clk_chan = (dma_channel_enum)drv->dma_chan[BS_DMA_CLOCK].chan;

    size += 1;
    drv->tx_count = size;
    for(int i=0; i<size; i++)
    {
        temp = *buf++;
        *dst++ = temp;
        *dst++ = ~temp;
    }

    // 2. 启动 SPI 发送通道
    SPI_CTL0(spix) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
    dma_single_data_parameter_struct dma_init_struct;

    /* enable DMA clock */
    dma_deinit(trans_dma, trans_chan);

    /* DMA channel5 initialize */
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(spix);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory0_addr = (uint32_t)drv->tx_buf;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;   // DMA_CIRCULAR_MODE_DISABLE
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.number = size*2;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(trans_dma, trans_chan, &dma_init_struct);
    dma_channel_subperipheral_select(trans_dma, trans_chan, trans_sub);

    /* enable DMA channel */
    dma_channel_enable(trans_dma, trans_chan);
    spi_dma_enable(spix, SPI_DMA_TRANSMIT);

    // 3. 启动 pwm
    drv->clock_data[size*16+2-1] = 0;

    /* disable DMA a channel */
    DMA_CHCTL(clk_dma, clk_chan) &= ~DMA_CHXCTL_CHEN;
    timer_dma_disable(timx, TIMER_DMA_UPD);
    
    /* reset DMA channel registers */
    dma_flag_clear(clk_dma, clk_chan, DMA_CHINTF_RESET_VALUE);
    DMA_CHCNT(clk_dma, clk_chan) = size*16+2;
        
    dma_channel_enable(clk_dma, clk_chan);
    timer_dma_enable(timx, TIMER_DMA_UPD);
}   


/*!
    \brief      pwm+dma: 阻塞读取
    \param[in]  none
    \param[out] none
    \retval     0: success，1:timeout
*/
int __v1_protocol_read(bs_writer_ctx_t *ctx, unsigned char * rdb, int size)
{
    uint8_t chan = ctx->channel;
    uint32_t time_out = 0;
    if (chan == 0)
    {
        (void)SPI_DATA(SPI1);
        SPI_CTL0(SPI0) &= (uint32_t)SPI_BIDIRECTIONAL_RECEIVE;
        while(size--)
        {
            /* reset PWM&DMA */    
            /* disable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH1) &= ~DMA_CHXCTL_CHEN;

            /* disable TIM update event */
            TIMER_DMAINTEN(TIMER1) &= (~(uint32_t)(TIMER_DMA_UPD));
            
            /* reset DMA channel registers */
            dma_flag_clear(DMA0, DMA_CH1, DMA_CHINTF_RESET_VALUE);

            /* configure dma number (8bit data + 1bit zero)*/
            DMA_CHCNT(DMA0, DMA_CH1) = 9;

            /* enable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH1) |= DMA_CHXCTL_CHEN;
            
            /* restart PWM */
            TIMER_DMAINTEN(TIMER1) |= (uint32_t) TIMER_DMA_UPD;

            /* wait PWM transmit complete & spi receive data */
            // while(RESET == dma_flag_get(DMA0, DMA_CH1, DMA_INTF_FTFIF));
            // while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));

            time_out = READ_TIME_OUT;
            while(RESET == dma_flag_get(DMA0, DMA_CH1, DMA_INTF_FTFIF))
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE))
            {
                if(time_out == 0) break;
                time_out--;
            };
            if(time_out == 0) return 1;   // time_out
            *rdb++ = SPI_DATA(SPI0);
        }
        SPI_CTL0(SPI0) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
    } else if (chan==1)
    {
        (void)SPI_DATA(SPI1);
        SPI_CTL0(SPI1) &= (uint32_t)SPI_BIDIRECTIONAL_RECEIVE;
        while(size--)
        {
            /* reset PWM&DMA */    
            /* disable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH2) &= ~DMA_CHXCTL_CHEN;

            /* disable TIM update event */
            TIMER_DMAINTEN(TIMER2) &= (~(uint32_t)(TIMER_DMA_UPD));
            
            /* reset DMA channel registers */
            dma_flag_clear(DMA0, DMA_CH2, DMA_CHINTF_RESET_VALUE);

            /* configure dma number (8bit data + 1bit zero)*/
            DMA_CHCNT(DMA0, DMA_CH2) = 9;

            /* enable DMA  channel */
            DMA_CHCTL(DMA0, DMA_CH2) |= DMA_CHXCTL_CHEN;
            
            /* restart PWM */
            TIMER_DMAINTEN(TIMER2) |= (uint32_t) TIMER_DMA_UPD;

            /* wait PWM transmit complete & spi receive data */
            // while(RESET == dma_flag_get(DMA0, DMA_CH2, DMA_INTF_FTFIF));
            // while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));

            time_out = READ_TIME_OUT;
            while(RESET == dma_flag_get(DMA0, DMA_CH2, DMA_INTF_FTFIF))
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
            {
                if(time_out == 0) break;
                time_out--;
            };
            if(time_out == 0) return 1;   // time_out
            *rdb++ = SPI_DATA(SPI1);
        }
        SPI_CTL0(SPI1) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
    }
    
    return 0;
}


/*!
    \brief      查询脉冲发送是否完毕
    \param[in]  none
    \param[out] none
    \retval     0: 忙，1:传输完成
*/
int __v2_protocol_ioctl(bs_writer_ctx_t *ctx,  bs_writer_trans_t cmd)
{
    int status=0;
    uint32_t time_out;
    switch(cmd)
    {
    case IOC_WR_END:
        status = (ctx->drv->pulse_cnt == 0xFFFF) ? 1: 0;
        if (status)
        {
            time_out = WRITE_TIME_OUT;
            while(SET == spi_i2s_flag_get(ctx->drv->spix, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            }
            spi_dma_disable(ctx->drv->spix, SPI_DMA_TRANSMIT);
            if(time_out == 0) ctx->schedu = WRITER_WR_TIME_OUT;
        }
    break;

    case IOC_RD_END:
        status = (ctx->drv->pulse_cnt == 0xFFFF) ? 1: 0;
        if (status)
        {
            time_out = READ_TIME_OUT;
            while(SET == spi_i2s_flag_get(ctx->drv->spix, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            }
            spi_dma_disable(ctx->drv->spix, SPI_DMA_RECEIVE);
            if(time_out == 0) ctx->schedu = WRITER_RD_TIME_OUT;
        }
    break;

    default:
    break;
    }
    return status;
}


/*!
    \brief      pwm+onePulse: 阻塞写入
    \param[in]  none
    \param[out] none
    \retval     0: success，1:timeout
*/
int __v2_protocol_write_sync(bs_writer_ctx_t *ctx, unsigned char *buf, int size)
{
	uint8_t chan = ctx->channel;
    uint32_t time_out = 0;
    if (chan == 0)
    {
        /* enable 3Line send */
        SPI_CTL0(SPI0) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
        while(size--)
        {
            // while(0 == SPI_STAT(SPI0) & SPI_FLAG_TBE);
            SPI_DATA(SPI0) = (uint32_t)(*buf++);
            timer_enable(TIMER0);
            time_out = WRITE_TIME_OUT;
            while(TIMER_CTL0(TIMER0) & 0x01)
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(SET == spi_i2s_flag_get(SPI0, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            };
            // (void)SPI_DATA(SPI0);
            if(time_out == 0) return 1;   // time_out
        }
    } else if (chan==1)
    {
        /* enable 3Line send */
        SPI_CTL0(SPI1) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
        while(size--)
        {
            // while(0 == SPI_STAT(SPI1) & SPI_FLAG_TBE);
            SPI_DATA(SPI1) = (uint32_t)(*buf++);
            timer_enable(TIMER7);
            time_out = WRITE_TIME_OUT;
            while(TIMER_CTL0(TIMER7) & 0x01)
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(SET == spi_i2s_flag_get(SPI1, SPI_FLAG_TRANS))
            {
                if(time_out == 0) break;
                time_out--;
            };
            // (void)SPI_DATA(SPI1);
            if(time_out == 0) return 1;   // time_out
        }
    } else {return 1;}
    return 0;
}


/*!
    \brief      阻塞读取
    \param[in]  none
    \param[out] none
    \retval     0: success，1:timeout
*/
int __v2_protocol_read(bs_writer_ctx_t *ctx, unsigned char * rdb, int size)
{
    uint8_t chan = ctx->channel;
    uint32_t time_out = 0;
    if (chan == 0)
    {
        (void)SPI_DATA(SPI1);
        SPI_CTL0(SPI0) &= (uint32_t)SPI_BIDIRECTIONAL_RECEIVE;
        while(size--)
        {
            /* emit clk */
            timer_enable(TIMER0);

            time_out = READ_TIME_OUT;
            while(TIMER_CTL0(TIMER0) & 0x01)
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE))
            {
                if(time_out == 0) break;
                time_out--;
            }; 

            if(time_out == 0) return 1;   // time_out
            *rdb++ = SPI_DATA(SPI0);
        }
        SPI_CTL0(SPI0) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
    } else if (chan==1)
    {
        (void)SPI_DATA(SPI1);
        SPI_CTL0(SPI1) &= (uint32_t)SPI_BIDIRECTIONAL_RECEIVE;
        while(size--)
        {
            /* emit clk */
            timer_enable(TIMER7);

            time_out = READ_TIME_OUT;
            while(TIMER_CTL0(TIMER7) & 0x01)
            {
                if(time_out == 0) break;
                time_out--;
            };
            while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE))
            {
                if(time_out == 0) break;
                time_out--;
            }; 

            if(time_out == 0) return 1;   // time_out
            *rdb++ = SPI_DATA(SPI1);
        }
        SPI_CTL0(SPI1) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
    }
    return 0;
}


/*!
    \brief      利用 spi dma发送批量数据，由重复计数器设定脉冲个数
    \param[in]  none
    \param[out] none
    \retval     0: success
*/
void __v2_protocol_write_async(bs_writer_ctx_t *ctx, unsigned char *buf, int size)
{
    // 1. 填充内容
    register uint8_t temp;
    bs_writer_drv_t *drv = ctx->drv;
    register uint8_t *dst = (uint8_t *)drv->tx_buf;
    uint32_t spix = drv->spix;
    uint32_t trans_dma = drv->dma_chan[BS_DMA_DATA_OUT].dmax;
    dma_channel_enum trans_chan = (dma_channel_enum)drv->dma_chan[BS_DMA_DATA_OUT].chan;
    dma_subperipheral_enum trans_sub = (dma_subperipheral_enum)drv->dma_chan[BS_DMA_DATA_OUT].sub_peri;
    uint32_t pulse_cnt;

    size += 1;
    drv->tx_count = size;
    drv->pulse_cnt = size * 16;
    for(int i=0; i<size; i++)
    {
        temp = *buf++;
        *dst++ = temp;
        *dst++ = ~temp;
    }

    // 2. 启动 SPI 发送通道
    SPI_CTL0(spix) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
    dma_single_data_parameter_struct dma_init_struct;

    /* initial SPI DMA */
    dma_deinit(trans_dma, trans_chan);

    /* DMA channel5 initialize */
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(spix);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory0_addr = (uint32_t)drv->tx_buf;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.number = size*2;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(trans_dma, trans_chan, &dma_init_struct);
    dma_channel_subperipheral_select(trans_dma, trans_chan, trans_sub);

    /* enable DMA channel */
    dma_channel_enable(trans_dma, trans_chan);
    spi_dma_enable(spix, SPI_DMA_TRANSMIT);

    /* 配置时钟脉冲数量 */
    pulse_cnt = BS_MIN(size*16 , 256);
    drv->pulse_cnt -= pulse_cnt;
    if(ctx->channel == 0)
    {
        /* disable DMA a channel */
        // timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_DISABLE);
        // timer_disable(TIMER0);
        timer_repetition_value_config(TIMER0, pulse_cnt-1);
        timer_event_software_generate(TIMER0, TIMER_EVENT_SRC_UPG);
        timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
        timer_interrupt_enable(TIMER0, TIMER_INT_UP);
        timer_enable(TIMER0);
        // timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_ENABLE);
    } else {
        timer_repetition_value_config(TIMER7, pulse_cnt-1);
        timer_event_software_generate(TIMER7, TIMER_EVENT_SRC_UPG);
        timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP);
        timer_interrupt_enable(TIMER7, TIMER_INT_UP);
        timer_enable(TIMER7);
    }
}


/*!
    \brief      利用 spi dma发送批量数据，由重复计数器设定脉冲个数
    \param[in]  none
    \param[out] none
    \retval     0: success
*/
void __v2_protocol_read_async(bs_writer_ctx_t *ctx, unsigned char *buf, int size)
{
    bs_writer_drv_t *drv = ctx->drv;
    uint32_t spix = drv->spix;
    uint32_t trans_dma = drv->dma_chan[BS_DMA_DATA_IN].dmax;
    dma_channel_enum trans_chan = (dma_channel_enum)drv->dma_chan[BS_DMA_DATA_IN].chan;
    dma_subperipheral_enum trans_sub = (dma_subperipheral_enum)drv->dma_chan[BS_DMA_DATA_IN].sub_peri;
    uint32_t pulse_cnt;

    size += 1;
    drv->pulse_cnt = size * 16;

    // 2. 启动 SPI 发送通道
    SPI_CTL0(spix) &= (uint32_t)SPI_BIDIRECTIONAL_RECEIVE;
    dma_single_data_parameter_struct dma_init_struct;

    /* initial SPI DMA */
    dma_deinit(trans_dma, trans_chan);

    /* DMA channel initialize */
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(spix);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory0_addr = (uint32_t)drv->rx_buf;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.number = size*2;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(trans_dma, trans_chan, &dma_init_struct);
    dma_channel_subperipheral_select(trans_dma, trans_chan, trans_sub);

    /* enable DMA channel */
    dma_channel_enable(trans_dma, trans_chan);
    (void)SPI_DATA(spix);
    SPI_CTL0(spix) &= (uint32_t)SPI_BIDIRECTIONAL_RECEIVE;
    spi_dma_enable(spix, SPI_DMA_RECEIVE);

    /* 配置时钟脉冲数量 */
    pulse_cnt = BS_MIN(size*16 , 256);
    drv->pulse_cnt -= pulse_cnt;
    if(ctx->channel == 0)
    {
        /* disable DMA a channel */
        // timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_DISABLE);
        // timer_disable(TIMER0);
        timer_repetition_value_config(TIMER0, pulse_cnt-1);
        timer_event_software_generate(TIMER0, TIMER_EVENT_SRC_UPG);
        timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
        timer_interrupt_enable(TIMER0, TIMER_INT_UP);
        timer_enable(TIMER0);
        // timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_ENABLE);
    } else {
        timer_repetition_value_config(TIMER7, pulse_cnt-1);
        timer_event_software_generate(TIMER7, TIMER_EVENT_SRC_UPG);
        timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP);
        timer_interrupt_enable(TIMER7, TIMER_INT_UP);
        timer_enable(TIMER7);
    }
}

